﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using Chianti.Service.Types;
using Chianti.Service.Types.Enumeration;
using Chianti.Service;


namespace Chianti.Service
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in code, svc and config file together.
    public class DealManagementService : IDealManagementService
    {
        private static bool isComptuingExpiration = false;

        public string GetData(int value)
        {
            return string.Format("You entered: {0}", value);
        }

        public CompositeType GetDataUsingDataContract(CompositeType composite)
        {
            if (composite == null)
            {
                throw new ArgumentNullException("composite");
            }
            if (composite.BoolValue)
            {
                composite.StringValue += "Suffix";
            }
            return composite;
        }

        public long CreateBusiness(Business newBusiness)
        {
            using (ChiantiDataClassesDataContext context = new ChiantiDataClassesDataContext())
            {
                context.Businesses.InsertOnSubmit(newBusiness);
                context.SubmitChanges();
                return newBusiness.ID;
            }
        }

        public void DeleteBusiness(long businessID)
        {
            //Business business = null;
            using (ChiantiDataClassesDataContext context = new ChiantiDataClassesDataContext())
            {
                var business =  (from b in context.Businesses
                                where b.ID == businessID
                                select b).First<Business>();

                if (business == null)
                {
                    throw new Exception(string.Format("DeleteBusiness: Cannot find business with id {0}", businessID));
                }
                context.Businesses.DeleteOnSubmit(business);
                context.SubmitChanges();
            }
        }

        public CreateDealResponse CreateDeal(Deal newDeal, double bidAmount, int radius)
        {
            ExpireObjectsInDatabase();
            CreateDealResponse retVal = new CreateDealResponse();
            
            if (newDeal.ID != default(long))
            {
                throw new Exception("ID of newly submitted deal must not be set prior to submission to Create");
            }

            using (ChiantiDataClassesDataContext context = new ChiantiDataClassesDataContext())
            {
                context.Deals.InsertOnSubmit(newDeal);
                context.SubmitChanges();
                retVal.DealID = newDeal.ID;

                DealBid dealBid = new DealBid();
                dealBid.DealID = newDeal.ID;
                dealBid.Date = DateTime.Now;
                dealBid.Radius = radius;
                dealBid.IsActive = true;

                context.DealBids.InsertOnSubmit(dealBid);
                context.SubmitChanges();
                
                //At this point the deal has been created in our store
                //Need to evaluate whether it is an "Active" bid meaning that it is both enabled
                //and its the highest bid over any overlapping deals
                DateTime currentDate = DateTime.Now;
                if (newDeal.ExpiryDate <= currentDate)
                {
                    return retVal;
                }

                List<Deal> overlappingDealsWithHigherBids = EvaluateNewDealBid(newDeal, dealBid);
                retVal.CompetingBids = ConvertDealsToBids(newDeal,overlappingDealsWithHigherBids);
                /*
                List<Deal> activeDeals = (from c in context.ActiveDeals
                                           join d in context.Deals
                                           on c.DealID equals d.ID
                                           select d).ToList<Deal>();

                List<Deal> dealsToDeactivate = new List<Deal>();
                bool shouldMakeNewDealActive = true;
                foreach (Deal activeDeal in activeDeals)
                {
                    //check to see if this deal overlaps with the deal being created
                    if (newDeal.DoesOverlap(activeDeal))
                    {
                        DealBid latestBid = (from d in context.DealBids
                                             where d.DealID == activeDeal.ID && d.IsActive == true
                                             select d).First<DealBid>();

                        if (dealBid.Bid > latestBid.Bid)
                        {
                            //the new bid is higher than an existing conflicting one
                            //the existing one should be removed
                            dealsToDeactivate.Add(activeDeal);
                            shouldMakeNewDealActive = true;
                        }
                        else
                        {
                            //the new bid is lower than an existing one, we can break with no changes
                            shouldMakeNewDealActive = false;
                            break;
                        }
                    }
                }

                //The new deal should be made active 
                if (shouldMakeNewDealActive)
                {
                    ActiveDeal newDealActive = new ActiveDeal();
                    newDealActive.DealID = newDeal.ID;
                    ActiveDeal.InsertIntoDatabase(context, newDealActive);
                    


                    //Remove conflicting deals from the activeDeal table
                    foreach (Deal dealToDeactivate in dealsToDeactivate)
                    {
                        ActiveDeal activeOldDeal = (from ad in context.ActiveDeals
                                                    where ad.DealID == dealToDeactivate.ID
                                                    select ad).First<ActiveDeal>();
                        context.ActiveDeals.DeleteOnSubmit(activeOldDeal);
                    }
                    context.SubmitChanges();
                   
                }
                else
                {
                    List<Deal> overlappingDealsWithHigherBids = GetOverlappingDealsWithHigherBid(newDeal);
                    retVal.CompetingBids = ConvertDealsToBids(newDeal,overlappingDealsWithHigherBids);

                   
                }
                */
            }
            return retVal;
        }

        /// <summary>
        /// Internal method which recalculates active deals based on the creation of a new DealBid object. Returns a list of all Deals which currently overlap the
        /// specified deal based on the new deal bid. An empty list implies that this deal is now active.
        /// </summary>
        /// <param name="newDeal"></param>
        /// <param name="dealBid"></param>
        internal List<Deal> EvaluateNewDealBid(Deal newDeal, DealBid dealBid)
        {
            List<Deal> retVal = new List<Deal>();
            using (ChiantiDataClassesDataContext context = new ChiantiDataClassesDataContext())
            {
                List<Deal> activeDeals = (from c in context.ActiveDeals
                                          join d in context.Deals
                                          on c.DealID equals d.ID
                                          select d).ToList<Deal>();

                List<Deal> dealsToDeactivate = new List<Deal>();

                bool shouldMakeNewDealActive = true;
                foreach (Deal activeDeal in activeDeals)
                {
                    //check to see if this deal overlaps with the deal being created
                    if (activeDeal.ID != newDeal.ID && newDeal.DoesOverlap(activeDeal))
                    {
                        DealBid latestBid = (from d in context.DealBids
                                             where d.DealID == activeDeal.ID && d.IsActive == true
                                             select d).First<DealBid>();

                        if (dealBid.Bid > latestBid.Bid)
                        {
                            //the new bid is higher than an existing conflicting one
                            //the existing one should be removed
                            dealsToDeactivate.Add(activeDeal);
                            shouldMakeNewDealActive = true;
                        }
                        else
                        {
                            //the new bid is lower than an existing one, we can break with no changes
                            shouldMakeNewDealActive = false;
                            break;
                        }
                    }
                }

                //The new deal should be made active 
                if (shouldMakeNewDealActive && !IsDealActive(newDeal.ID))
                {
                    ActiveDeal newDealActive = new ActiveDeal();
                    newDealActive.DealID = newDeal.ID;
                    ActiveDeal.InsertIntoDatabase(context, newDealActive);



                    //Remove conflicting deals from the activeDeal table
                    foreach (Deal dealToDeactivate in dealsToDeactivate)
                    {
                        ActiveDeal activeOldDeal = (from ad in context.ActiveDeals
                                                    where ad.DealID == dealToDeactivate.ID
                                                    select ad).First<ActiveDeal>();
                        context.ActiveDeals.DeleteOnSubmit(activeOldDeal);
                    }
                    context.SubmitChanges();

                }
                else if (!shouldMakeNewDealActive)
                {
                    if (IsDealActive(newDeal.ID))
                    {
                        //we need to deactivate the deal in the active deals table
                        ActiveDeal existingDeal = (from ad in context.ActiveDeals
                                                  where ad.DealID == newDeal.ID
                                                  select ad).First<ActiveDeal>();
                        context.ActiveDeals.DeleteOnSubmit(existingDeal);
                        context.SubmitChanges();
                    }

                    retVal = GetOverlappingActiveDealsWithHigherBid(newDeal);

                }
            }

            return retVal;
        }

        /// <summary>
        /// Returns a boolean indicating whether the Deal specified with ID is active.
        /// </summary>
        /// <param name="p"></param>
        /// <returns></returns>
        public bool IsDealActive(long dealID)
        {
            ExpireObjectsInDatabase();
            using (ChiantiDataClassesDataContext context = new ChiantiDataClassesDataContext())
            {
                var result = from c in context.ActiveDeals
                             where c.DealID == dealID
                             select c;
                if (result.Count() == 0)
                {
                    return false;
                }
                else
                {
                    return true;
                }
            }
        }

        internal List<Bid> ConvertDealsToBids(Deal sourceDeal, List<Deal> deals)
        {
            List<Bid> retVal = new List<Bid>();
            foreach (Deal deal in deals)
            {
                DealBid overlappingDealBid = GetLatestDealBid(deal);
                Bid bid = new Bid();
                bid.BidAmount = overlappingDealBid.Bid;
                bid.ExpiryDate = deal.ExpiryDate;
                bid.Distance = PositionCalculator.GetDistanceInMeters(sourceDeal.Business.Longitude, sourceDeal.Business.Latitude, deal.Business.Longitude, deal.Business.Latitude);
                retVal.Add(bid);
            }
            return retVal;
        }

        public void UpdateDeal(Deal updatedDeal)
        {
            if (updatedDeal.ID == default(long))
            {
                throw new Exception("UpdateDeal: Cannot update Deal with no valid ID value set");
            }

            if (updatedDeal.BusinessID == default(long))
            {
                throw new Exception("UpdateDeal: Cannot update Deal with no valid BusinessID value set");
            }



            using (ChiantiDataClassesDataContext context = new ChiantiDataClassesDataContext())
            {
                var result = (from c in context.Deals
                              where c.ID == updatedDeal.ID
                              select c);

                if (result.Count() == 0)
                {
                    throw new Exception(string.Format("UpdateDeal: Object with ID: {0} because it does not exist", updatedDeal.ID));
                }

                Deal newDeal = result.First() as Deal;
                newDeal.CreationDate = updatedDeal.CreationDate;
                newDeal.Description = updatedDeal.Description;
                newDeal.ExpiryDate = updatedDeal.ExpiryDate;
                newDeal.Title = updatedDeal.Title;
                newDeal.Video = updatedDeal.Video;
                newDeal.Image = updatedDeal.Image;
                newDeal.BusinessID = updatedDeal.BusinessID;
                context.SubmitChanges();
            }

        }

        //TODO: add new methods to update video and image files as they are large and shouldnt be sent
        //across the wire unless needed.

       
        public UpdateDealBidResponse UpdateDealBid(long dealID, double newBid, int newBidRadius)
        {
            ExpireObjectsInDatabase();
            DateTime currentDate = DateTime.Now;
            UpdateDealBidResponse retVal = new UpdateDealBidResponse();
            List<Deal> overlappingDealsWithHigherBids = new List<Deal>();

            using (ChiantiDataClassesDataContext context = new ChiantiDataClassesDataContext())
            {
                Deal deal = (from c in context.Deals
                             where c.ID == dealID
                             select c).First<Deal>();

                if (deal == null || currentDate > deal.ExpiryDate)
                {
                    throw new Exception(string.Format("UpdateDealBid: Deal with id:{0} cannot be found or is expired", dealID));
                }

                DealBid existingBid = (from db in context.DealBids
                                       where db.DealID == dealID && db.IsActive == true
                                       select db).First<DealBid>();

                existingBid.IsActive = false;
                
                DealBid newDealBid = new DealBid();
                newDealBid.DealID = dealID;
                newDealBid.Date = currentDate;
                newDealBid.Bid = newBid;
                newDealBid.Radius = newBidRadius;
                newDealBid.IsActive = true;

                context.DealBids.InsertOnSubmit(newDealBid);
                
                context.SubmitChanges();

                //find any overlapping deals with a higher bid
                overlappingDealsWithHigherBids = EvaluateNewDealBid(deal, newDealBid);
                //overlappingDealsWithHigherBids = GetOverlappingDealsWithHigherBid(deal);
                retVal.CompetingBids = ConvertDealsToBids(deal,overlappingDealsWithHigherBids);
               
            }

            return retVal;
        }

        private void ExpireObjectsInDatabase()
        {
            if (!DealManagementService.isComptuingExpiration)
            {
                isComptuingExpiration = true;
                DateTime currentDate = DateTime.Now;

                using (ChiantiDataClassesDataContext context = new ChiantiDataClassesDataContext())
                {

                    var newlyExpiredActiveDeals = from ad in context.ActiveDeals
                                                  join d in context.Deals on
                                                  ad.DealID equals d.ID
                                                  where d.IsActive == true && d.ExpiryDate <= currentDate
                                                  select ad;

                    //loop through each active deal, look for deals that overlap it and are not active
                    //for each deal that overlaps, check to see if its the highest active bidder in its radius
                    //create a list of all potential active deals to replace the one that is expired
                    foreach (ActiveDeal expiredDeal in newlyExpiredActiveDeals)
                    {
                        Deal deal = GetDeal(expiredDeal.DealID);
                        List<Deal> candidateReplacementDeals = new List<Deal>();
                        List<Deal> overlappingDeals = GetOverlappingDeals(deal);
                        //now we have a list of deals which overlap this one, we need to determine whether they themselves
                        //are active deals independent of the removal of this one
                        foreach (Deal overlappingDeal in overlappingDeals)
                        {
                            List<Deal> overlappingDealsWithHigherBids = GetOverlappingDealsWithHigherBid(overlappingDeal);
                            if (overlappingDealsWithHigherBids.Count == 0)
                            {
                                candidateReplacementDeals.Add(overlappingDeal);
                            }
                        }

                        //now we have a list of candidate deals to activate
                        foreach (Deal dealToActivate in candidateReplacementDeals)
                        {
                            ActiveDeal newlyActivatedDeal = new ActiveDeal();
                            newlyActivatedDeal.DealID = dealToActivate.ID;
                            context.ActiveDeals.InsertOnSubmit(newlyActivatedDeal);
                            context.SubmitChanges();
                        }

                    }

                    //now we need to expire all deals from the deal table
                    var expiredDeals = from d in context.Deals
                                       where currentDate > d.ExpiryDate && d.IsActive == true
                                       select d;

                    foreach (Deal expiredDeal in expiredDeals)
                    {
                        ExpireDeal(expiredDeal.ID);

                    }
                    context.SubmitChanges();
                    isComptuingExpiration = false;
                }
            }
        }

        private void ExpireDeal(long dealID)
        {
            using (ChiantiDataClassesDataContext context = new ChiantiDataClassesDataContext())
            {
                var activeDeal = from d in context.Deals
                                 where d.ID == dealID
                                 select d;

                if (activeDeal == null || activeDeal.Count() != 1)
                {
                    throw new Exception(string.Format("ExpireDeal: Deal with ID:{0} does not exist",dealID));
                }

                Deal expiredDeal = activeDeal.First<Deal>();
                ExpireActiveDeal(expiredDeal);
                ExpireDealBids(expiredDeal);
                expiredDeal.IsActive = false;
                context.SubmitChanges();
            }
        }
        private void ExpireActiveDeal(Deal deal)
        {
            using (ChiantiDataClassesDataContext context = new ChiantiDataClassesDataContext())
            {
                var activeDeal = (from ad in context.ActiveDeals
                                  where ad.DealID == deal.ID
                                  select ad);
                
                
                if (activeDeal != null && activeDeal.Count() != 0)
                {
                    ActiveDeal activeDealObj = activeDeal.First<ActiveDeal>();
                    context.ActiveDeals.DeleteOnSubmit(activeDealObj);
                    context.SubmitChanges();
                }
            }
        }

        /// <summary>
        /// Returns a list of active (non-expired) deals which have an active bid that overlaps the specified deal
        /// </summary>
        /// <param name="deal"></param>
        /// <returns></returns>
        private List<Deal> GetOverlappingDeals(Deal deal)
        {
            List<Deal> retVal = new List<Deal>();
            DateTime currentDate = DateTime.Now;

            using (ChiantiDataClassesDataContext context = new ChiantiDataClassesDataContext())
            {
                DealBid newestDealbid = (from d in context.DealBids
                                         where d.DealID == deal.ID && d.IsActive == true
                                         select d).First<DealBid>();


                Position dealLongitude = new Position(deal.Business.Longitude);
                Position dealLatitude = new Position(deal.Business.Latitude);

                List<Deal> overlappingDeals = FindDeals(dealLongitude, dealLatitude, newestDealbid.Radius);

                foreach (Deal overlappingDeal in overlappingDeals)
                {
                    if (overlappingDeal.ID != deal.ID && overlappingDeal.ExpiryDate > currentDate)
                    {
                       
                            retVal.Add(overlappingDeal);
                        
                    }
                }
            }

            return retVal;
        }

        private void ExpireDealBids(Deal expiredDeal)
        {
            using (ChiantiDataClassesDataContext context = new ChiantiDataClassesDataContext())
            {
                var results = from db in context.DealBids
                              where db.DealID == expiredDeal.ID && db.IsActive == true
                              select db;


                if (results != null)
                {
                    DealBid expiredDealBid = results.First<DealBid>();
                    if (expiredDealBid != null)
                    {
                        expiredDealBid.IsActive = false;

                        context.SubmitChanges();
                    }
                }
            }
        }


        /// <summary>
        /// Returns a list of active  & non-expired Deals which overlap with the passed in deal and that have
        /// higher bids
        /// </summary>
        /// <param name="dealID"></param>
        /// <returns></returns>
        internal List<Deal> GetOverlappingActiveDealsWithHigherBid(Deal deal)
        {
            List<Deal> retVal = new List<Deal>();
            DateTime currentDate = DateTime.Now;
            using (ChiantiDataClassesDataContext context = new ChiantiDataClassesDataContext())
            {
                DealBid newestDealbid = (from d in context.DealBids
                                         where d.DealID == deal.ID && d.IsActive == true
                                         select d).First<DealBid>();
               

                Position dealLongitude = new Position(deal.Business.Longitude);
                Position dealLatitude = new Position(deal.Business.Latitude);

                List<Deal> overlappingDeals = FindActiveDeals(dealLongitude, dealLatitude, newestDealbid.Radius);

                foreach (Deal overlappingDeal in overlappingDeals)
                {
                    if (overlappingDeal.ID != deal.ID && overlappingDeal.ExpiryDate > currentDate)
                    {
                        DealBid latestBid = GetLatestDealBid(overlappingDeal);
                        if (latestBid.Bid > newestDealbid.Bid)
                        {
                            retVal.Add(overlappingDeal);
                        }
                    }
                }
            }

            return retVal;
        }


        /// <summary>
        /// Returns a list of non-expired Deals which overlap with the passed in deal and that have
        /// higher bids
        /// </summary>
        /// <param name="dealID"></param>
        /// <returns></returns>
        internal List<Deal> GetOverlappingDealsWithHigherBid(Deal deal)
        {
            List<Deal> retVal = new List<Deal>();
            DateTime currentDate = DateTime.Now;
            using (ChiantiDataClassesDataContext context = new ChiantiDataClassesDataContext())
            {
                DealBid newestDealbid = (from d in context.DealBids
                                         where d.DealID == deal.ID && d.IsActive == true
                                         select d).First<DealBid>();


                Position dealLongitude = new Position(deal.Business.Longitude);
                Position dealLatitude = new Position(deal.Business.Latitude);

                List<Deal> overlappingDeals = FindDeals(dealLongitude, dealLatitude, newestDealbid.Radius);

                foreach (Deal overlappingDeal in overlappingDeals)
                {
                    if (overlappingDeal.ID != deal.ID && overlappingDeal.ExpiryDate > currentDate)
                    {
                        DealBid latestBid = GetLatestDealBid(overlappingDeal);
                        if (latestBid.Bid > newestDealbid.Bid)
                        {
                            retVal.Add(overlappingDeal);
                        }
                    }
                }
            }

            return retVal;
        }

        /// <summary>
        /// Returns the latest submitted bid for a particular deal. Returns an empty list in the case of no
        /// deal bids being present.
        /// </summary>
        /// <param name="deal"></param>
        /// <returns></returns>
        internal DealBid GetLatestDealBid(Deal deal)
        {
            DealBid retVal = null;
            using (ChiantiDataClassesDataContext context = new ChiantiDataClassesDataContext())
            {
                retVal = (from c in context.DealBids
                          where c.DealID == deal.ID && c.IsActive == true
                          select c).First<DealBid>();
            }

            return retVal;
            
        }

        //TODO: need to add mechanism for executing expiring deals

        public void DeleteDeal(long dealID)
        {
            if (DoesDealExist(dealID))
            {
                using (ChiantiDataClassesDataContext context = new ChiantiDataClassesDataContext())
                {
                    Deal deal = GetDeal(dealID,context);
                    context.Deals.DeleteOnSubmit(deal);
                    context.SubmitChanges();
                }
            }
            else
            {
                throw new Exception(string.Format("DeleteDeal: Cannot delete deal with ID: {0} as it doesn't exist", dealID));
            }

        }

        private bool DoesDealExist(long dealID)
        {
            using (ChiantiDataClassesDataContext context = new ChiantiDataClassesDataContext())
            {
                var result = from c in context.Deals
                             where c.ID == dealID
                             select c;

                if (result.Count() != 1)
                {
                    return false;
                }
            }
            return true;
        }

        public Deal GetDeal(long dealID)
        {
            ChiantiDataClassesDataContext context = new ChiantiDataClassesDataContext();
            return GetDeal(dealID, context);
        
        }

        private Deal GetDeal(long dealID, ChiantiDataClassesDataContext context)
        {
            var result = (from c in context.Deals
                          where c.ID == dealID
                          select c);

            if (result.Count() == 0)
            {
                throw new Exception(string.Format("Could not find Deal with ID: {0}", dealID));
            }
            else if (result.Count() > 1)
            {
                throw new Exception(string.Format("Found multiple deals with ID: {0}", dealID));
            }
            else
            {
                return result.First();
            }
        }


        public List<DealEnumerationResult> FindDealHeadings(Position longitude, Position latitude, int radius, int maxResults)
        {
            List<DealEnumerationResult> retVal = new List<DealEnumerationResult>();
            List<Deal> nearbyDeals = FindActiveDeals(longitude, latitude, radius, maxResults);

            foreach (Deal deal in nearbyDeals)
            {
                DealEnumerationResult dealIdentitfier = new DealEnumerationResult();
                dealIdentitfier.ID = deal.ID;
                dealIdentitfier.Title = deal.Title;
                dealIdentitfier.Business = deal.Business;
                dealIdentitfier.Description = deal.Description;
                retVal.Add(dealIdentitfier);
            }

            return retVal;
            


        }

        public DealMetric GetDealMetrics(long dealID)
        {
            using (ChiantiDataClassesDataContext context = new ChiantiDataClassesDataContext())
            {
                var result = from c in context.DealMetrics
                             where c.DealID == dealID
                             select c;
                if (result.Count() == 0)
                {
                    throw new Exception(string.Format("Could not find deal with id: {0}",dealID));
                }
                else if (result.Count() > 1)
                {
                    throw new Exception(string.Format("Found multiple deal metric records for deal with id:{0}", dealID));

                }
                else
                {
                    return result.First();
                }
            }
        }


        public List<Business> FindBusinessesByName(string name, int maxResults)
        {
            using (ChiantiDataClassesDataContext context = new ChiantiDataClassesDataContext())
            {
                var result = from b in context.Businesses
                             where b.Name.StartsWith(name)
                             select b;

                if (result.Count() < maxResults)
                {
                    return result.ToList<Business>();
                }
                else
                {
                    return result.Take(maxResults).ToList<Business>();
                }
            }
        }

        
        internal List<Deal> FindActiveDeals(Position longitude, Position latitude, int radius)
        {
            return FindActiveDeals(longitude,latitude,radius,int.MaxValue);
        }

        /// <summary>
        /// Returns all non-expired deals which are within the specified radius. Will include inactive deals.
        /// </summary>
        /// <param name="longitude"></param>
        /// <param name="latitude"></param>
        /// <param name="radius"></param>
        /// <returns></returns>
        internal List<Deal> FindDeals(Position longitude, Position latitude, int radius)
        {
            ExpireObjectsInDatabase();
            List<Deal> retVal = new List<Deal>();

            //algorithm
            //for each active deal in the database
            //  evaluate whether its in the radius from the current location
            //  return a list of all deals in the radius

            using (ChiantiDataClassesDataContext context = new ChiantiDataClassesDataContext())
            {

                List<DealBid> activeDealBids = (from db in context.DealBids
                                                where db.IsActive == true
                                                select db).ToList<DealBid>();

                //We have a list of all active deals
                foreach (DealBid activeDealBid in activeDealBids)
                {
                    Deal deal = (from d in context.Deals
                                 where d.ID == activeDealBid.DealID
                                 select d).First<Deal>();

                    Position dealLatitude = new Position(deal.Business.Latitude);
                    Position dealLongitude = new Position(deal.Business.Longitude);

                    double distance = PositionCalculator.GetDistanceInMeters(longitude, latitude, dealLongitude, dealLatitude);

                    if ((distance - activeDealBid.Radius) <= radius)
                    {
                        retVal.Add(deal);
                    }
                }
            }
            return retVal.ToList<Deal>();
        }

        public List<Deal> FindActiveDeals(Position longitude, Position latitude, int radius, int maxResults)
        {
            ExpireObjectsInDatabase();
            List<Deal> retVal = new List<Deal>();

            //algorithm
            //for each active deal in the database
            //  evaluate whether its in the radius from the current location
            //  return a list of all deals in the radius

            using (ChiantiDataClassesDataContext context = new ChiantiDataClassesDataContext())
            {

                List<DealBid> activeDealBids = (from d in context.ActiveDeals
                                                join db in context.DealBids
                                                on d.DealID equals db.DealID
                                                where db.IsActive == true
                                                select db).ToList<DealBid>();

                //We have a list of all active deals
                foreach (DealBid activeDealBid in activeDealBids)
                {
                    Deal deal = (from d in context.Deals
                                 where d.ID == activeDealBid.DealID
                                 select d).First<Deal>();

                    Position dealLatitude = new Position(deal.Business.Latitude);
                    Position dealLongitude = new Position(deal.Business.Longitude);

                    double distance = PositionCalculator.GetDistanceInMeters(longitude, latitude, dealLongitude, dealLatitude);

                    if ((distance - activeDealBid.Radius) <= radius)
                    {
                        retVal.Add(deal);
                    }
                }
            }
            return retVal.Take<Deal>(maxResults).ToList<Deal>();

               
        }


        public Business GetBusiness(long businessID)
        {
            Business retVal = null;

            using (ChiantiDataClassesDataContext context = new ChiantiDataClassesDataContext())
            {
                retVal = GetBusiness(businessID, context);
            }

            return retVal;
        }

        private Business GetBusiness(long businessID, ChiantiDataClassesDataContext context)
        {
            var result = from c in context.Businesses
                         where c.ID == businessID
                         select c;

            if (result.Count() != 1)
            {
                throw new Exception(string.Format("GetBusiness: Unable to find a business with ID: {0}", businessID));
            }
            else
            {
                return result.First<Business>();
            }
        }

        public List<DealBid> GetDealBids(List<long> dealIDs)
        {
            List<DealBid> retVal = new List<DealBid>();

            using (ChiantiDataClassesDataContext context = new ChiantiDataClassesDataContext())
            {
                foreach (long dealID in dealIDs)
                {
                    retVal.Add(GetDealBid(dealID));
                }
            }
            return retVal;
        }

        public DealBid GetDealBid(long dealID)
        {
            using (ChiantiDataClassesDataContext context = new ChiantiDataClassesDataContext())
            {
                var results = from db in context.DealBids
                              where db.DealID == dealID && db.IsActive == true
                              select db;

                if (results == null || results.Count() == 0)
                {
                    throw new Exception(string.Format("GetDealBid: Cannot find any deal bids associated with dealID {0}",dealID));
                }
                else
                {
                    return results.First<DealBid>();
                }
            }
        }

        public List<Business> GetBusinesses(List<long> businessIDs)
        {
            List<Business> retVal = new List<Business>();

            using (ChiantiDataClassesDataContext context = new ChiantiDataClassesDataContext())
            {
                foreach (long id in businessIDs)
                {
                    retVal.Add(GetBusiness(id));
                }
            }
            return retVal;
        }
    }
}
